/**
 代码修改历史纪录
 -----------------------------------------------------------------------------
 修改人  |    修改日期   |  审核人  |   修改内容
 ------------|-----------------------|---------------|--------------------------
 */
package band.wukong.practice.util.mess;

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * <p>Title: band.wukong.practice.java.util.DateUtil</p>
 * <p>Description: Reflect工具类</p>
 * <p>Copyright: free</p>
 * <p>Date: 2008-3-14 上午11:56:30</p>
 *
 * @author jsun
 * @version 0.1
 */
public class ReflectUtils {

    /**
     * 得到某对象的private属性
     *
     * @param obj       对象
     * @param fieldName 属性名
     * @return 该属性对象
     * @throws Exception
     */
    public static Object getPrivateProperty(Object obj, String fieldName) throws Exception {
        //得到该对象的Class
        Class clazz = obj.getClass();
        //通过Class得到类声明的属性
        Field field = clazz.getDeclaredField(fieldName);
        //设定对私有属性的访问权限
        field.setAccessible(true);

        //通过对象得到该属性的实例
        return field.get(obj);
    }

    /**
     * 得到某对象的public属性
     *
     * @param obj       对象
     * @param fieldName 属性名
     * @return 该属性对象
     * @throws Exception
     */
    public static Object getPublicProperty(Object obj, String fieldName) throws Exception {
        //得到该对象的Class
        Class clazz = obj.getClass();
        //通过Class得到类声明的属性
        Field field = clazz.getField(fieldName);
        //通过对象得到该属性的实例，如果这个属性是非公有的，这里会报IllegalAccessException
        return field.get(obj);
    }

    /**
     * 得到某个类的static属性
     *
     * @param className 类名
     * @param fieldName 属性名
     * @return 该对象属性
     * @throws Exception
     */
    public static Object getStaticProperty(String className, String fieldName) throws Exception {
        //首先得到这个类的Class
        Class clazz = Class.forName(className);
        //通过Class得到类声明的属性
        Field field = clazz.getField(fieldName);
        //因为该属性是静态的，所以直接从类的Class里取
        return field.get(clazz);
    }

    /**
     * 执行对象的有参public方法
     *
     * @param obj        对象
     * @param methodName 方法名
     * @param args       参数数组
     * @return
     * @throws Exception
     */
    public static Object invokeMethod(Object obj, String methodName, Object[] args) throws Exception {

        //得到这个对象的Class
        Class clazz = obj.getClass();
        //配置参数的Class数组，作为寻找Method的条件
        Class[] clazzArray = new Class[args.length];
        for (int i = 0, j = args.length; i < j; i++) {
            clazzArray[i] = args[i].getClass();
        }

        //通过Method名和参数的Class数组得到要执行的Method
        Method method = clazz.getMethod(methodName, clazzArray);

        //执行该Method，invoke方法的参数是执行这个方法的对象，和参数数组。
        //返回值是Object，也既是该方法的返回值
        return method.invoke(obj, args);
    }

    /**
     * 执行对象的无参public方法
     *
     * @param obj        对象
     * @param methodName 方法名
     * @return Object，也既是该方法的返回值
     * @throws Exception
     */
    public static Object invokeMethodWithNoParam(Object obj, String methodName) throws Exception {
        //得到这个对象的Class
        Class clazz = obj.getClass();
        //通过Method名和参数的Class数组得到要执行的Method
        Method method = clazz.getMethod(methodName);
        //执行该Method，invoke方法的参数是执行这个方法的对象
        return method.invoke(obj);
    }

    /**
     * 执行某类的public static方法
     *
     * @param className  类名
     * @param methodName 方法名
     * @param args       参数数组
     * @return 执行方法返回的结果
     * @throws Exception
     */
    public static Object invokeStaticMethod(String className, String methodName,
                                            Object[] args) throws Exception {

        /*	基本的原理和invokeMethod()相同，
          不同点是最后一行，invoke的一个参数是null，
          因为这是静态方法，不需要借助实例运行。*/

        Class clazz = Class.forName(className);
        Class[] argsClass = new Class[args.length];
        for (int i = 0, j = args.length; i < j; i++) {
            argsClass[i] = args[i].getClass();
        }
        Method method = clazz.getMethod(methodName, argsClass);

        return method.invoke(null, args);
    }

    /**
     * 新建类的实例
     *
     * @param className 类名
     * @param args      构造函数的参数
     * @return 新建的实例
     * @throws Exception
     */
    public static Object newInstance(String className, Object[] args) throws Exception {

        /*	这里说的方法是执行带参数的构造函数来新建实例的方法。
          如果不需要参数，可以直接使用clazz.newInstance()来实现。*/

        Class clazz = Class.forName(className);

        //得到参数的Class数组
        Class[] argsClass = new Class[args.length];
        for (int i = 0, j = args.length; i < j; i++) {
            argsClass[i] = args[i].getClass();
        }
        //得到构造器
        Constructor cons = clazz.getConstructor(argsClass);

        //返回新建的实例
        return cons.newInstance(args);
    }

    /**
     * 判断是不是某个类的实例
     *
     * @param obj 实例
     * @param cls 类
     * @return 如果obj是此类的实例，则返回true
     */
    public static boolean isInstance(Object obj, Class cls) {
        return cls.isInstance(obj);
    }

    /**
     * 得到数组中的某个元素
     *
     * @param array 数组
     * @param index 索引
     * @return 返回指定数组对象中索引组件的值
     */
    public static Object getByArray(Object array, int index) {
        return Array.get(array, index);
	}
}
